using System.Diagnostics.CodeAnalysis;
using YMJake.Flowable.ExternalWorker.Client.Core.Variables;

namespace YMJake.Flowable.ExternalWorker.Client.Core.Client;

/// <summary>
/// Extension methods for type-safe variable access on external worker jobs
/// </summary>
public static class ExternalWorkerJobExtensions
{
    /// <summary>
    /// Get a string variable value directly
    /// </summary>
    public static string? GetStringVariable(this IAcquiredExternalWorkerJob job, string variableName)
    {
        if (job.Variables.TryGetValue(variableName, out var value))
        {
            return value?.ToString();
        }
        return null;
    }

    /// <summary>
    /// Get an integer variable value directly
    /// </summary>
    public static int? GetIntegerVariable(this IAcquiredExternalWorkerJob job, string variableName)
    {
        if (job.Variables.TryGetValue(variableName, out var value))
        {
            return ConvertToInt(value);
        }
        return null;
    }

    /// <summary>
    /// Get a boolean variable value directly
    /// </summary>
    public static bool? GetBooleanVariable(this IAcquiredExternalWorkerJob job, string variableName)
    {
        if (job.Variables.TryGetValue(variableName, out var value))
        {
            return ConvertToBool(value);
        }
        return null;
    }

    /// <summary>
    /// Get a double variable value directly
    /// </summary>
    public static double? GetDoubleVariable(this IAcquiredExternalWorkerJob job, string variableName)
    {
        if (job.Variables.TryGetValue(variableName, out var value))
        {
            return ConvertToDouble(value);
        }
        return null;
    }

    /// <summary>
    /// Get a date variable value directly
    /// </summary>
    public static DateTime? GetDateVariable(this IAcquiredExternalWorkerJob job, string variableName)
    {
        if (job.Variables.TryGetValue(variableName, out var value))
        {
            return ConvertToDateTime(value);
        }
        return null;
    }

    /// <summary>
    /// Try to get a string variable (simplified version)
    /// </summary>
    public static bool TryGetVariable(this IAcquiredExternalWorkerJob job, string variableName, out StringVariable? variable)
    {
        variable = null;
        if (job.Variables.TryGetValue(variableName, out var value) && value != null)
        {
            variable = new StringVariable(value.ToString() ?? "");
            return true;
        }
        return false;
    }

    private static int? ConvertToInt(object? value)
    {
        return value switch
        {
            int i => i,
            long l when l >= int.MinValue && l <= int.MaxValue => (int)l,
            double d when d >= int.MinValue && d <= int.MaxValue && d == Math.Floor(d) => (int)d,
            string s when int.TryParse(s, out var result) => result,
            _ => null
        };
    }

    private static long? ConvertToLong(object? value)
    {
        return value switch
        {
            long l => l,
            int i => i,
            double d when d >= long.MinValue && d <= long.MaxValue && d == Math.Floor(d) => (long)d,
            string s when long.TryParse(s, out var result) => result,
            _ => null
        };
    }

    private static double? ConvertToDouble(object? value)
    {
        return value switch
        {
            double d => d,
            float f => f,
            int i => i,
            long l => l,
            string s when double.TryParse(s, out var result) => result,
            _ => null
        };
    }

    private static bool? ConvertToBool(object? value)
    {
        return value switch
        {
            bool b => b,
            string s when bool.TryParse(s, out var result) => result,
            _ => null
        };
    }

    private static DateTime? ConvertToDateTime(object? value)
    {
        return value switch
        {
            DateTime dt => dt,
            DateTimeOffset dto => dto.DateTime,
            string s when DateTime.TryParse(s, out var result) => result,
            _ => null
        };
    }
}